package zhizhemodi.tech.short_term_bwork.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

@Component
@ServerEndpoint("/websocket/{deviceId}")
public class WebSocketServer {

    /**
     * 保存所有连接的webSocket实体
     * CopyOnWriteArrayList使用了一种叫写时复制的方法,
     * 当有新元素添加到CopyOnWriteArrayList时，
     * 先从原有的数组中拷贝一份出来，然后在新的数组做写操作,
     * 写完之后，再将原来的数组引用指向到新数组。
     * 具备线程安全，并且适用于高并发场景
     */
    private static CopyOnWriteArrayList<WebSocketServer> sWebSocketServers = new CopyOnWriteArrayList<>();
    Session mSession;
    Integer mdeviceId;
    private Log mLog = LogFactory.getLog(WebSocketServer.class);
    private static List<Integer> confirmList = new ArrayList<>();

    @OnOpen
    public void OnOpen(Session session, @PathParam("deviceId") Integer deviceId) {
        mSession = session;
        sWebSocketServers.add(this);
        mLog.info("--->onOpen new connect deviceId is " + deviceId);
        mdeviceId = deviceId;
    }

    @OnClose
    public void onClose() {
        sWebSocketServers.remove(this);
        mLog.info("-->onClose a connect");
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        JSONObject jmessage = (JSONObject)JSON.parse(message);
        for(String key : jmessage.keySet()) {
            mLog.info("-->onMessage:" + this.mdeviceId + "key: " + key + ",value: " + jmessage.getString(key));
        }
        if(this.mdeviceId <= 0) {
            if(jmessage.get("deviceId") != null) sendMessage(jmessage.getString("msg"), jmessage.getInteger("deviceId"));
        }
        if(this.mdeviceId > 0) {
            if(jmessage.getString("type").equals("confirm")){
                if(jmessage.getInteger("planId") > 0) confirmList.add(jmessage.getInteger("planId")); 
            }
        }
    }

    /**
     * 发送消息
     * @param message
     */
    public boolean sendMessage(String message) {
        try {
            mSession.getBasicRemote().sendText(message);
        } catch (IOException e) {
            mLog.info(e.toString());
            return false;
        }
        return true;
    }

    /**
     * 对一些机器发送消息
     * @param message
     * @param devices 机器编号组
     * @return true, 返回发送的消息， false， 返回failed 
     */
    public static String sendMessage(String message, Integer device) {
        boolean success = false;
        for (WebSocketServer server : sWebSocketServers) {
            if(server.mdeviceId == device) {
                success = server.sendMessage(message);
            }
        }
        return success ? message : "failed";
    }

    /**
     * 对一些机器发送消息
     * @param message
     * @param devices 机器编号组
     * @return true, 返回发送的消息， false， 返回failed 
     */
    public static String sendMessage(String message, List<Integer> devices) {
        boolean success = false;
        for (WebSocketServer server : sWebSocketServers) {
            if(devices.contains(server.mdeviceId)) {
                success = server.sendMessage(message);
            }
        }
        return success ? message : "failed";
    }

    /**
     * 
     * @param message
     * @param devices
     * @return
     */
    public static Boolean sendMessage(Map<String, Object> message, List<Integer> devices) {
        Boolean success = false;
        for (WebSocketServer server : sWebSocketServers) {
            if(devices.contains(server.mdeviceId)) {
                success = server.sendMessage(message.toString());
            }
        }
        return success ? true : false;
    }

    /**
     * 
     * @return
     */
    public List<Integer> getConfirmList() {
        List<Integer> re = new ArrayList<>();
        for(Integer id : confirmList) {
            re.add(id);
        }
        confirmList.clear();
        return re;
    }
}
